#include "stdafx.h"
#include "CompAndCandWnd.h"
#include "ImmStuff.h"
#include "BitmapEx.h"
#include "GlobalData.h"
#include "ImmData.h"
#include "KnowledgeBase.h"

BOOL CompAndCandWnd::Register(HINSTANCE hInstance)
{
	WNDCLASSEX wc;
	//
    // register class of composition window.
    //
    wc.cbSize         = sizeof(WNDCLASSEX);
    wc.style          = CS_PYGINPUT | CS_IME;
    wc.lpfnWndProc    = CompAndCandWndWndProc;
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = UICHILDEXTRASIZE;
    wc.hInstance      = hInstance;
    wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
    wc.hIcon          = NULL;
    wc.lpszMenuName   = NULL;
    wc.lpszClassName  = CompAndCandClassName;
    wc.hbrBackground  = NULL;
    wc.hIconSm        = NULL;
	
    if( !RegisterClassEx( (LPWNDCLASSEX)&wc ) )
        return FALSE;
	return TRUE;
}

VOID CompAndCandWnd::UnRegister(HINSTANCE hInstance)
{
	UnregisterClass(CompAndCandClassName,hInstance);
}

VOID CompAndCandWnd::CreateWnd(HWND hUIWnd, LPUIEXTRA lpUIExtra)
{
	if (!IsWindow(lpUIExtra->uiComp.hWnd))
    {
		HDC hDC;
		lpUIExtra->uiComp.hWnd = 
            CreateWindowEx( WS_EX_WINDOWEDGE,
                         CompAndCandClassName,NULL,
                         WS_DISABLED | WS_POPUP | WS_DLGFRAME,
                         0,
                         0,
                         1,
						 1,
                         hUIWnd,NULL,ImmStuff::hInst,NULL);
		SetWindowLong(lpUIExtra->uiComp.hWnd,FIGWL_SVRWND,(DWORD)hUIWnd);		

		lpUIExtra->uiComp.sz.cx = 1;
		lpUIExtra->uiComp.sz.cy = 1;
    }
    ShowWindow(lpUIExtra->uiComp.hWnd,SW_HIDE);
    return;
}

VOID CompAndCandWnd::DrawUIBorder(LPRECT lprc)
{
	HDC hDC;
	int sbx, sby;

	hDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL );
	SelectObject( hDC, GetStockObject( GRAY_BRUSH ) );
	sbx = GetSystemMetrics( SM_CXBORDER );
	sby = GetSystemMetrics( SM_CYBORDER );
	PatBlt( hDC, lprc->left, 
		lprc->top, 
		lprc->right - lprc->left-sbx, 
		sby, PATINVERT );
	PatBlt( hDC, lprc->right - sbx, 
		lprc->top, 
		sbx, 
		lprc->bottom - lprc->top-sby, PATINVERT );
	PatBlt( hDC, lprc->right, 
		lprc->bottom-sby, 
		-(lprc->right - lprc->left-sbx), 
		sby, PATINVERT );
	PatBlt( hDC, lprc->left, 
		lprc->bottom, 
		sbx, 
		-(lprc->bottom - lprc->top-sby), PATINVERT );
	DeleteDC( hDC );
}

VOID CompAndCandWnd::DragUI( HWND hWnd, HWND hWnd1,UINT message, WPARAM wParam, LPARAM lParam,BOOL fIsCompWnd)
{
	POINT     pt;
	static    POINT ptdif,ptdif1;
	static    RECT drc,drc1;
	static    SIZE sz,sz1;
	DWORD     dwT;

	switch (message)
	{
	case WM_SETCURSOR:
		if ( HIWORD(lParam) == WM_LBUTTONDOWN
			|| HIWORD(lParam) == WM_RBUTTONDOWN ) 
		{
			GetCursorPos( &pt );
			SetCapture(hWnd);
			GetWindowRect(hWnd,&drc);
			ptdif.x = pt.x - drc.left;
			ptdif.y = pt.y - drc.top;
			sz.cx = drc.right - drc.left;
			sz.cy = drc.bottom - drc.top;

			if (IsWindow(hWnd1)) {
				GetWindowRect(hWnd1,&drc1);
				ptdif1.x = pt.x - drc1.left;
				ptdif1.y = pt.y - drc1.top;
				sz1.cx = drc1.right - drc1.left;
				sz1.cy = drc1.bottom - drc1.top;
			}

			SetWindowLong(hWnd,FIGWL_MOUSE,FIM_CAPUTURED);
		}
		break;

	case WM_MOUSEMOVE:
		dwT = GetWindowLong(hWnd,FIGWL_MOUSE);
		if (dwT & FIM_MOVED)
		{
			DrawUIBorder(&drc);
			if (IsWindow(hWnd1)) DrawUIBorder(&drc1);
			GetCursorPos( &pt );
			drc.left   = pt.x - ptdif.x;
			drc.top    = pt.y - ptdif.y;
			drc.right  = drc.left + sz.cx;
			drc.bottom = drc.top + sz.cy;
			if (IsWindow(hWnd1)) {
				drc1.left   = pt.x - ptdif1.x;
				drc1.top    = pt.y - ptdif1.y;
				drc1.right  = drc1.left + sz1.cx;
				drc1.bottom = drc1.top + sz1.cy;
			}
			DrawUIBorder(&drc);
			if (IsWindow(hWnd1)) DrawUIBorder(&drc1);
		}
		else if (dwT & FIM_CAPUTURED)
		{
			DrawUIBorder(&drc);
			if (IsWindow(hWnd1)) DrawUIBorder(&drc1);
			SetWindowLong(hWnd,FIGWL_MOUSE,dwT | FIM_MOVED);
		}
		break;

	case WM_LBUTTONUP:
	case WM_RBUTTONUP:
		dwT = GetWindowLong(hWnd,FIGWL_MOUSE);

		if (dwT & FIM_CAPUTURED)
		{
			ReleaseCapture();
			if (dwT & FIM_MOVED)
			{
				DrawUIBorder(&drc);
				if (IsWindow(hWnd1)) DrawUIBorder(&drc1);
				GetCursorPos( &pt );
				MoveWindow(hWnd,pt.x - ptdif.x,
					pt.y - ptdif.y,
					sz.cx,
					sz.cy,TRUE);

				if(fIsCompWnd) {
					HWND hUIWnd;
					LPARAM mylParam;

					*((LPWORD)(&mylParam)) = (WORD)(pt.x - ptdif.x);
					*((LPWORD)(&mylParam)+1) = (WORD)(pt.y - ptdif.y);

					hUIWnd = (HWND)GetWindowLong(hWnd,FIGWL_SVRWND);
					if (IsWindow(hUIWnd))
						SendMessage(hUIWnd,WM_UI_COMPMOVE,0,mylParam);
				}

				if (IsWindow(hWnd1)) {
					MoveWindow(hWnd1,pt.x - ptdif1.x,
						pt.y - ptdif1.y,
						sz1.cx,
						sz1.cy,TRUE);
				}
			}
		}
		break;
	}
}

VOID CompAndCandWnd::Move(HWND hUIWnd, LPUIEXTRA lpUIExtra, HIMC hIMC)
{
	if (!IsWindow(lpUIExtra->uiComp.hWnd))
		CreateWnd( hUIWnd, lpUIExtra);

	if (IsWindow(lpUIExtra->uiComp.hWnd))
	{
		HDC hDC;
		POINT pt;
		RECT screenrc;
		SIZE sz;

		sz.cx = 0;
		sz.cy = 0;
		hDC = GetDC(lpUIExtra->uiComp.hWnd);

		ImmData immData(hIMC);
		if(!immData.LockImmOK() || !immData.IsCompStr())
		{
			ShowWindow(lpUIExtra->uiComp.hWnd, SW_HIDE);
			return;
		}

		UINT baseCount = 0;
		UINT compAreaLen = 0;
		if(0 == immData.GetCompStrClass()->GetInputLen())
		{
			ShowWindow(lpUIExtra->uiComp.hWnd, SW_HIDE);
			return;
		}
		for(UINT i = 0;i < immData.GetCompStrClass()->GetInputLen(); ++i)
		{
			if(std::wstring(immData.GetCompStrClass()->GetInput(i).baseCode).size() > 1)
				baseCount ++;
		}
		compAreaLen = baseCount * (IMG_WIDTH + PAINT_MARGIN);// 2 piexl for margin.

		std::wstring comStr = immData.GetCompStrClass()->GetCompositionString();
		
		GetTextExtentPoint(hDC,comStr.c_str(),comStr.size(),&sz);
		sz.cx += PAINT_MARGIN;

		sz.cx = sz.cx > compAreaLen ? sz.cx : compAreaLen;
		if(baseCount > 0)
			sz.cy += (IMG_HEIGHT + PAINT_MARGIN); // draw base image.
		else sz.cy += PAINT_MARGIN / 2;
		sz.cy += PAINT_MARGIN; // center separate line.


		UINT pageStart = immData.GetCandStrClass()->GetCurrentPageStart();
		UINT pageSize = immData.GetCandStrClass()->GetPageSize();
		UINT candCount = immData.GetCandStrClass()->GetCandidateCount();
		UINT count = (pageStart + pageSize) >= candCount ? (candCount - pageStart) : pageSize;
		UINT candAreaLen = 0;
		SIZE size;
		std::wstring testTxt(_T("A"));
		std::wstring pageArow(_T("<< >>"));
		GetTextExtentPoint(hDC,testTxt.c_str(),testTxt.size(),&size);
		candAreaLen = count * (IMG_WIDTH + PAINT_MARGIN + size.cx);
		GetTextExtentPoint(hDC,pageArow.c_str(),pageArow.size(),&size);
		candAreaLen += size.cx;

		sz.cx = sz.cx > candAreaLen ? sz.cx : candAreaLen;
		sz.cy +=  (IMG_HEIGHT + PAINT_MARGIN / 2);
	
		ReleaseDC(lpUIExtra->uiComp.hWnd,hDC);
		sz.cx += 4 * GetSystemMetrics(SM_CXEDGE);
		sz.cy += 4 * GetSystemMetrics(SM_CYEDGE);

		lpUIExtra->uiComp.sz.cx = sz.cx;
		lpUIExtra->uiComp.sz.cy = sz.cy;

		if(lpUIExtra->uiComp.pt.x < 0) {
			pt.x = 15;
			pt.y = 15;
			ClientToScreen(immData.GetAppWnd(), &pt);
		}
		else{
			pt.x = lpUIExtra->uiComp.pt.x;
			pt.y = lpUIExtra->uiComp.pt.y;
		}

		SystemParametersInfo(SPI_GETWORKAREA,0,&screenrc,0);

		if( (pt.x + sz.cx) > screenrc.right )
			pt.x = screenrc.right - sz.cx;
		if( (pt.y + sz.cy) > screenrc.bottom )
			pt.y = screenrc.bottom - sz.cy;

		MoveWindow(lpUIExtra->uiComp.hWnd,pt.x,pt.y,sz.cx,sz.cy,TRUE);

		ShowWindow(lpUIExtra->uiComp.hWnd, SW_SHOWNOACTIVATE);
		InvalidateRect(lpUIExtra->uiComp.hWnd,NULL,TRUE);
	}
}

VOID CompAndCandWnd::HideWnd(LPUIEXTRA lpUIExtra)
{
	if (IsWindow(lpUIExtra->uiComp.hWnd))
    {
        ShowWindow(lpUIExtra->uiComp.hWnd, SW_HIDE);
    }
}

VOID CompAndCandWnd::Paint(HWND hWnd)
{
	PAINTSTRUCT ps;
    HIMC hIMC;
    LPINPUTCONTEXT lpIMC;
    LPCOMPOSITIONSTRING lpCompStr;
	LPCANDIDATELIST lpCandList;
	LPCANDIDATEINFO lpCandInfo;
    HDC hDC;
    RECT rc;
    HWND hSvrWnd;
	HWND hCompWnd = hWnd;
	HBRUSH hBrush = (HBRUSH)NULL;
	HBRUSH hOldBrush = (HBRUSH)NULL;
	HPEN hPen = (HPEN)NULL;
	HPEN hOldPen = (HPEN)NULL;
	UINT left,top;
	UINT compInputLen = 0;

    hDC = BeginPaint(hCompWnd,&ps);

	GetClientRect(hCompWnd,&rc);

	hBrush = (HBRUSH)GetStockObject(DC_BRUSH);
	hOldBrush = (HBRUSH)SelectObject(hDC,hBrush);
	PatBlt(hDC,
			rc.left,
			rc.top ,
			rc.right - GetSystemMetrics(SM_CXEDGE)/2,
			rc.bottom - GetSystemMetrics(SM_CYEDGE)/2,
			PATCOPY);
	if(hBrush && hOldBrush)
		SelectObject(hDC,hOldBrush);

	hPen = (HPEN)GetStockObject(WHITE_PEN);
	hOldPen = (HPEN)SelectObject(hDC,hPen);
	MoveToEx(hDC,0,rc.bottom - GetSystemMetrics(SM_CXEDGE)/2,NULL);
	LineTo(hDC,rc.right-GetSystemMetrics(SM_CXEDGE)/2,rc.bottom - GetSystemMetrics(SM_CXEDGE)/2);
	LineTo(hDC,rc.right-GetSystemMetrics(SM_CXEDGE)/2,0);

	hPen = CreatePen(PS_SOLID ,0,RGB(128,128,128));
	SelectObject(hDC,hPen);
	MoveToEx(hDC,rc.right-GetSystemMetrics(SM_CXEDGE)/2,0,NULL);
	LineTo(hDC,0,0);
	LineTo(hDC,0,rc.bottom-GetSystemMetrics(SM_CYEDGE)/2);	

	SelectObject(hDC,hOldPen);
	DeleteObject(hPen);

    hSvrWnd = (HWND)GetWindowLong(hCompWnd,FIGWL_SVRWND);

    if (hIMC = (HIMC)GetWindowLong(hSvrWnd,IMMGWL_IMC))
    {
		ImmData immData(hIMC);
		if(!immData.LockImmOK() || !immData.IsCompStr())
		{
			EndPaint(hCompWnd,&ps);
			return;
		}

		SIZE sz,sz1;
		SHORT wCount = 0;
		std::wstring compStr = immData.GetCompStrClass()->GetCompositionString();
		left = PAINT_MARGIN / 2;
		top = PAINT_MARGIN / 2;
		SetBkMode(hDC,TRANSPARENT);
		SetTextColor(hDC,RGB(0,0,0));
		TextOut(hDC,left,top,compStr.c_str(),compStr.size());
		
		GetTextExtentPoint(hDC,compStr.c_str(),compStr.size(),&sz);
		GetTextExtentPoint(hDC,_T("A"),1,&sz1);
		hPen = CreatePen(PS_SOLID,3,RGB(0,0,0));
		hOldPen = (HPEN)SelectObject(hDC,hPen);
		MoveToEx(hDC,sz.cx + sz1.cx/4,sz1.cy*11/10,NULL);
		LineTo(hDC,sz.cx + sz1.cx*2/3,sz1.cy*11/10);
		SelectObject(hDC,hOldPen);
		DeleteObject(hPen);

		MoveToEx(hDC,0,rc.bottom-GetSystemMetrics(SM_CYEDGE)/2 - (IMG_HEIGHT + PAINT_MARGIN),NULL);
		LineTo(hDC,rc.right-GetSystemMetrics(SM_CXEDGE)/2,rc.bottom-GetSystemMetrics(SM_CYEDGE)/2 - (IMG_HEIGHT + PAINT_MARGIN));				


		top += sz.cy + PAINT_MARGIN / 2;
		for(UINT i = 0; i < immData.GetCompStrClass()->GetInputLen(); ++i)
		{
			std::wstring baseCode(immData.GetCompStrClass()->GetInput(i).baseCode);
			if(baseCode.size() > 1)
			{
				CBitmapEx cbe;
				cbe.Load(GlobalData::GetInstance()->GetBmpAddr(stdex::ToMbString(baseCode)));
				cbe.Draw(hDC,left,top);
				left += (IMG_WIDTH + PAINT_MARGIN);
				compInputLen ++;
			}
		}

		UINT count = 0;
		UINT pageStart = immData.GetCandStrClass()->GetCurrentPageStart();
		UINT pageSize = immData.GetCandStrClass()->GetPageSize();
		UINT candCount = immData.GetCandStrClass()->GetCandidateCount();
		
		left = PAINT_MARGIN / 2;

		if(compInputLen > 0)
			top += (PAINT_MARGIN + IMG_HEIGHT);
		else
			top += PAINT_MARGIN;

		count = (pageStart + pageSize) >= candCount ? (candCount - pageStart) : pageSize;
		SetTextColor(hDC,RGB(0,0,0));

		for(UINT i = 0; i < count; ++i)
		{
			SIZE size;				
			UINT index = (i + 1) % 10;
			std::wstring order = stdex::itoaw(index);
			TextOut(hDC,left,top,order.c_str(),order.size());
			GetTextExtentPoint(hDC,order.c_str(),order.size(),&size);
			left += size.cx;
			
			std::wstring candStr = immData.GetCandStrClass()->GetCode(pageStart + i);
			if(KnowledgeProcess::Multiple || candStr.size() == 1)
			{
				TextOut(hDC,left+3,top+8,candStr.c_str(),candStr.size());
			}
			else
			{
				CBitmapEx cbe;
				cbe.Load(GlobalData::GetInstance()->GetBmpAddr(stdex::ToMbString(candStr)));
				cbe.Draw(hDC,left,top);
			}
			left += (IMG_WIDTH + PAINT_MARGIN);				
		}

		SIZE size;
		std::wstring txt(_T("<<"));		
		if(immData.GetCandStrClass()->HavePreviousPage())
		{
			SetTextColor(hDC,RGB(0,0,0));		
		}
		else
		{
			SetTextColor(hDC,RGB(0xE0,0xE0,0xE0));
		}
		GetTextExtentPoint(hDC,txt.c_str(),txt.size(),&size);
		TextOut(hDC,left,top + (IMG_HEIGHT - size.cy) / 2,txt.c_str(),txt.size());			
		left += size.cx;
		std::wstring txt2(_T(" >>"));
		if(immData.GetCandStrClass()->HaveNextPage())
		{
			SetTextColor(hDC,RGB(0,0,0));					
		}
		else
		{
			SetTextColor(hDC,RGB(0xE0,0xE0,0xE0));
		}
		TextOut(hDC,left,top + (IMG_HEIGHT - size.cy) / 2,txt2.c_str(),txt2.size());

    }
	ReleaseDC(hWnd,hDC);
    EndPaint(hCompWnd,&ps);
}


LRESULT WINAPI CompAndCandWndWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HWND  hUIWnd;
    HGLOBAL hUIExtra;
    LPUIEXTRA lpUIExtra;

	hUIWnd = (HWND)GetWindowLong(hWnd,FIGWL_SVRWND);
    hUIExtra = (HGLOBAL)GetWindowLong(hUIWnd,IMMGWL_PRIVATE);
	lpUIExtra = (LPUIEXTRA)GlobalLock(hUIExtra);

    switch (message)
    {
        case WM_PAINT:
			CompAndCandWnd::Paint(hWnd);
            break;

        case WM_SETCURSOR:
        case WM_MOUSEMOVE:
        case WM_LBUTTONUP:
        case WM_RBUTTONUP:
            CompAndCandWnd::DragUI(hWnd,lpUIExtra->uiCand.hWnd,message,wParam,lParam,TRUE);
            if ((message == WM_SETCURSOR) &&
                (HIWORD(lParam) != WM_LBUTTONDOWN) &&
                (HIWORD(lParam) != WM_RBUTTONDOWN)) 
                return DefWindowProc(hWnd,message,wParam,lParam);
            if ((message == WM_LBUTTONUP) || (message == WM_RBUTTONUP))
                SetWindowLong(hWnd,FIGWL_MOUSE,0L);
			CompAndCandWnd::Paint(hWnd);
            break;

        default:
            if (!ImmData::IsIMEMessage(message)) {
				GlobalUnlock(hUIExtra);
                return DefWindowProc(hWnd,message,wParam,lParam);
			}
            break;
    }
    GlobalUnlock(hUIExtra);
    return 0;
}